//! 函数相关练习
//! @author XQ Lin
//! @email xqlin@qq.com
//!

const std = @import("std");
const debug = std.debug.print;

pub fn run() void {
    debug("Zig函数练习\n", .{});

    // TODO: 闭包未完成练习
    // // closure
    // const closure = bar(5);
    // const counter = closure(8);
    // print("闭包计算结果：{}\n", .{counter});

    // anytype
    var intRes: i32 = add_anytype(100, 123);
    var fltRes: f64 = add_anytype(3.14, 1.0);
    // NOTE:不能直接用于字符串的相加
    // const str = add_anytype("Hello,", "Zig" );
    debug("ayntype 整数:{},浮点数:{}\n", .{ intRes, fltRes });
    intRes = add_numtype(5, 7);
    fltRes = add_numtype(2.1, 3.4);
    debug("anytype 整数:{},浮点数:{}\n", .{ intRes, fltRes });
    intRes = add_comptime(i32, 5, 8);
    fltRes = add_comptime(f64, 3.1, 8.3);
    debug("comptime 整数:{}, 浮点数：{}\n", .{ intRes, fltRes });
}

// 闭包函数
// fn bar(comptime x: i32) fn (i32) i32 {
//     return struct { // 匿名结构体
//         // 计算从 x 到 y 之间所有偶数的平方和
//         pub fn foo(y: i32) i32 { // pub
//             var counter: i32 = 0;
//             // for (x..y) |i| { // NOTE: for迭代是usize类型，不能是i32
//             var i: i32 = x;
//             while (x <= y) : (i += 1) {
//                 // NOTE: 在 Zig 中，% 运算符默认只适用于无符号整数（例如 u32, usize），
//                 // 因为 % 的行为在有符号整数上可能产生歧义（比如负数取模）。
//                 // 对于有符号整数（如 i32），需要显式使用以下两个函数之一来明确你的意图
//                 // @mod(i, 2) 返回数学意义上的模运算结果（非负）
//                 // @rem(i, 2) 返回 C 风格的余数（符号与被除数相同）
//                 // if (i % 2 == 0)
//                 if (@mod(x, 2) == 0)
//                     counter += i * i;
//             }
//             return counter;
//         }
//     }.foo;
// }

// fn bar(comptime x: i32) fn (i32) i32 {
//     return struct {
//         pub fn foo(y: i32) i32 {
//             var counter = 0;
//             for (x..y) |i| {
//                 if ((i % 2) == 0) {
//                     counter += i * i;
//                 }
//             }
//             return counter;
//         }
//     }.foo;
// }

// NOTE: anytype 与泛型有何区别？
fn add_anytype(x: anytype, y: anytype) @TypeOf(x) {
    return x + y;
}

fn add_numtype(x: anytype, y: anytype) @TypeOf(x) {
    return switch (@TypeOf(x)) {
        comptime_int, comptime_float => x + y,
        else => @compileError("不支持的类型"),
    };
}

// 使用comptime类型实现泛型功能，实际上用comptime是比泛型更好的。
// 编译时加法（增强类型安全）
fn add_comptime(comptime T: type, x: T, y: T) T {
    comptime { // NOTE: 最新2025中，显式编译期上下文
        if (!isNumeric(T)) {
            @compileError("类型 " ++ @typeName(T) ++ " 不是数值类型。");
        }
    }
    return x + y;
}

// NOTE:最新2025,函数参数的 comptime 关键字已经移到类型前面，而不是参数名前面。
// comptime fn isNumeric(comptime T: type) bool {
// 在 Zig 中，只有函数参数需要显式标记 comptime，函数本身不需要。
// 只要函数的参数被标记为 comptime，这个函数就可以在编译时执行。
// 判断一个编译时类型是否为数值类型

// 类型检查函数（适配2025小写标签）
fn isNumeric(comptime T: type) bool {
    const info = @typeInfo(T);
    return switch (info) { // NOTE: 也是类型反映的例子
        // NOTE: 2025采用全小写标签（当前版本仍用首字母大写）
        .int, .float, .comptime_int, .comptime_float => true,
        else => false,
    };
}
